#ifndef _SCHED_H_
#define _SCHED_H_

#define NR_TASKS 64
#define HZ 100

#define FIRST_TASK  task[0]
#define LAST_TASK   task[NR_TASKS - 1]

#include <linux/head.h>
#include <linux/fs.h>
#include <linux/mm.h>
#include <signal.h>

#define TASK_RUNNING            0
#define TASK_INTERRUPTIBLE      1
#define TASK_UNINTERRUPTIBLE    2
#define TASK_ZOMBIE             3
#define TASK_STOPPED            4

#ifndef NULL
#define NULL ((void *) 0)
#endif

extern int copy_page_tables(unsigned long from, unsigned long to, long size);
extern int free_page_tables(unsigned long from, unsigned long size);

extern void sched_init(void);
extern void schedule(void);
extern void trap_init(void);
typedef int (*fn_ptr)();

struct i387_struct {
    long    cwd;    // 控制字
    long    swd;    // 状态字
    long    twd;    // 标记字
    long    fip;    // 协处理器代码指针
    long    fcs;    // 协处理器代码段寄存器
    long    foo;    // 内存操作数的偏移值
    long    fos;    // 内存操作数的段值
    long    st_space[20];   // 8个10字节的协处理器累加器
};

struct tss_struct {
    long    back_link;  /* 16 high bits zero */
    long    esp0;
    long    ss0;        /* 16 high bits zero */
    long    esp1;
    long    ss1;        /* 16 high bits zero */
    long    esp2;
    long    ss2;        /* 16 high bits zero */
    long    cr3;
    long    eip;
    long    eflags;
    long    eax,ecx,edx,ebx;
    long    esp;
    long    ebp;
    long    esi;
    long    edi;
    long    es;         /* 16 high bits zero */
    long    cs;         /* 16 high bits zero */
    long    ss;         /* 16 high bits zero */
    long    ds;         /* 16 high bits zero */
    long    fs;         /* 16 high bits zero */
    long    gs;         /* 16 high bits zero */
    long    ldt;        /* 16 high bits zero */
    long    trace_bitmap;   /* bits: trace 0, bitmap 16-31 */
    struct i387_struct i387;
};

struct task_struct {
    long state;     // 任务的运行状态（-1 不可运行，0 可运行（就绪），>0 已停止）
    long counter;   // 任务运行时间计数（递减），时间片
    long priority;  // 任务运行优先级。任务刚开始时counter=priority，越大运行时间越长
    long signal;    // 信号。位图形式，每个比特位代表一种信号，信号值=位偏移值+1
    struct sigaction sigaction[32];
    long blocked;   // 任务信号屏蔽码
    int exit_code;  // 任务执行停止的退出码，其父进程会取
    // 代码段地址，代码长度，代码长度+数据长度，总长度，堆栈段地址
    unsigned long start_code, end_code, end_data, brk, start_stack;
    // 进程号，父进程号，进程组号，会话号，会话首领
    long pid, father, pgrp, session, leader;
    unsigned short uid, euid, suid; // 用户id，有效用户id，保存的用户id
    unsigned short gid, egid, sgid; // 组id，有效组id，保存的组id
    long alarm; // 报警定时值（滴答数）
    // 用户态运行时间，系统态运行时间，子进程用户态运行时间，子进程系统态运行时间，进程开始运行时刻
    long utime, stime, cutime, cstime, start_time;
    unsigned short used_math;   // 标志：是否使用了协处理器
    int tty;    // 进程使用的tty的子设备号。-1表示没有使用
    unsigned short umask;   // 文件创建属性屏蔽位
    unsigned long close_on_exec;    // 执行时关闭文件句柄位图标志
    struct desc_struct ldt[3];  // 任务局部描述符表。0-空，1-代码段，2-数据和堆栈段
    struct tss_struct tss;      // 进程的任务状态段信息
};

#define INIT_TASK \
/* state etc */ { 0, 15, 15, \
/* signal... */ 0, {{},}, 0, \
/* ec,brk... */ 0, 0, 0, 0, 0, 0, \
/* pid etc.. */ 0, -1, 0, 0, 0, \
/* uid etc */   0, 0, 0, 0, 0, 0, \
/* alarm */     0, 0, 0, 0, 0, 0, \
/* math */      0, \
/* tty etc */   -1, 0022,0, \
    { \
        {0, 0}, \
/* ldt */   {0x9f, 0xc0fa00}, \
        {0x9f, 0xc0f200}, \
    }, \
/*tss*/ {0, PAGE_SIZE + (long)&init_task, 0x10, 0, 0, 0, 0, (long)&pg_dir,\
        0, 0, 0, 0, 0, 0, 0, 0, \
        0, 0, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, \
        _LDT(0), 0x80000000, \
        {}  \
    }, \
}

extern struct task_struct *task[NR_TASKS];
extern struct task_struct *last_task_used_math;
extern struct task_struct *current;
extern long volatile jiffies;
extern long startup_time;

#define FIRST_TSS_ENTRY 4
#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY + 1)
#define _TSS(n) ((((unsigned long) n) << 4) + (FIRST_TSS_ENTRY << 3))
#define _LDT(n) ((((unsigned long) n) << 4) + (FIRST_LDT_ENTRY << 3))
#define ltr(n) __asm__("ltr %%ax"::"a"(_TSS(n)))
#define lldt(n) __asm__("lldt %%ax"::"a"(_LDT(n)))
#define str(n) \
__asm__("str %%ax\n\t" \
    "subl %2, %%eax\n\t" \
    "shrl $4, %%eax" \
    :"=a"(n) \
    :"a"(0), "i"(FIRST_TSS_ENTRY << 3))

#define switch_to(n) {\
struct {long a, b;} __tmp; \
__asm__("cmpl %%ecx, current\n\t" \
    "je 1f\n\t" \
    "movw %%dx, %1\n\t" \
    "xchgl %%ecx, current\n\t" \
    "ljmp *%0\n\t" \
    "cmpl %%ecx, last_task_used_math\n\t" \
    "jne 1f\n\t" \
    "clts\n" \
    "1:" \
    ::"m"(*&__tmp.a), "m"(*&__tmp.b), \
    "d"(_TSS(n)), "c"((long) task[n])); \
}

#define _set_base(addr, base)  \
__asm__ ("push %%edx\n\t" \
    "movw %%dx, %0\n\t" \
    "rorl $16, %%edx\n\t" \
    "movb %%dl, %1\n\t" \
    "movb %%dh, %2\n\t" \
    "pop %%edx" \
    ::"m"(*((addr) + 2)), \
    "m"(*((addr) + 4)), \
    "m"(*((addr) + 7)), \
    "d"(base) \
    )

#define set_base(ldt, base) _set_base(((char *)&(ldt)), (base))

static inline unsigned long _get_base(char * addr)
{
    unsigned long __base;
    __asm__("movb %3, %%dh\n\t"
            "movb %2, %%dl\n\t"
            "shll $16, %%edx\n\t"
            "movw %1, %%dx"
            :"=&d"(__base)
            :"m"(*((addr) + 2)),
            "m"(*((addr) + 4)),
            "m"(*((addr) + 7)));
    return __base;
}

#define get_base(ldt) _get_base(((char *)&(ldt)))

#define get_limit(segment) ({ \
unsigned long __limit; \
__asm__("lsll %1, %0\n\tincl %0":"=r"(__limit):"r"(segment)); \
__limit;})

#endif
